"""
SimpleAPI ORM 数据库连接管理

提供简化的数据库连接和管理接口，完全封装 Tortoise ORM 的数据库操作。
用户只需要使用这个接口，无需了解底层的 Tortoise 数据库管理。
"""

import asyncio
import inspect
import sys
import types
from typing import List, Dict, Any, Optional, Union
from tortoise import Tortoise, connections
from tortoise.models import Model as TortoiseModel
import logging

logger = logging.getLogger(__name__)


class Database:
    """
    数据库连接管理器
    
    提供简化的数据库连接、初始化和管理功能。
    """
    
    def __init__(self):
        self._initialized = False
        self._config = None
        self._discovered_models = []
        
    async def connect(self, 
                     url: str,
                     models: List[str] = None,
                     auto_discover: bool = True,
                     generate_schemas: bool = False,
                     app_name: str = "default") -> None:
        """
        连接数据库
        
        Args:
            url: 数据库连接 URL
            models: 模型模块列表，如果为 None 且 auto_discover=True 则自动发现
            auto_discover: 是否自动发现模型类
            generate_schemas: 是否自动生成数据库表结构
            app_name: 应用名称
        """
        if self._initialized:
            logger.warning("数据库已经初始化")
            return
            
        if not url:
            raise ValueError("必须提供数据库连接 URL")
        
        # 如果没有指定模型且启用自动发现
        if not models and auto_discover:
            models = self._discover_models()
            logger.info(f"自动发现模型: {models}")
        
        if not models:
            raise ValueError("未找到任何模型，请指定 models 参数或启用 auto_discover")
            
        self._config = {
            "connections": {"default": url},
            "apps": {
                app_name: {
                    "models": models,
                    "default_connection": "default",
                }
            },
        }
        
        # 如果有直接发现的模型类，需要特殊处理
        if self._discovered_models:
            # 创建一个临时模块来存放模型
            temp_module = types.ModuleType("models")
            temp_module.__file__ = "<auto_discovered>"
            
            # 将模型类添加到临时模块
            for model_class in self._discovered_models:
                setattr(temp_module, model_class.__name__, model_class)
            
            # 将临时模块添加到 sys.modules
            sys.modules["models"] = temp_module
            
        await Tortoise.init(self._config)
        
        if generate_schemas:
            await Tortoise.generate_schemas()
            
        self._initialized = True
        logger.info("数据库连接初始化完成")
        
    async def disconnect(self) -> None:
        """断开数据库连接"""
        if self._initialized:
            await Tortoise.close_connections()
            self._initialized = False
            logger.info("数据库连接已关闭")
            
    def _discover_models(self) -> List[str]:
        """
        自动发现当前环境中的模型类
        
        Returns:
            发现的模型类列表
        """
        discovered = []
        
        # 获取调用栈，找到调用 connect 的模块
        frame = inspect.currentframe()
        try:
            # 向上查找调用栈，找到非 ORM 内部的调用
            while frame:
                frame = frame.f_back
                if frame and frame.f_globals.get('__name__') not in [
                    'simpleapi.orm.database', 
                    'simpleapi.orm.models',
                    '__main__'
                ]:
                    caller_module = frame.f_globals.get('__name__')
                    if caller_module:
                        discovered.append(caller_module)
                        break
                elif frame and frame.f_globals.get('__name__') == '__main__':
                    # 如果是在 __main__ 中调用，扫描当前模块的所有 Model 类
                    main_models = []
                    for name, obj in frame.f_globals.items():
                        if (inspect.isclass(obj) and 
                            issubclass(obj, TortoiseModel) and 
                            obj != TortoiseModel and
                            not getattr(obj._meta, 'abstract', False)):
                            main_models.append(obj)
                    
                    if main_models:
                        # 将模型类直接注册
                        self._discovered_models = main_models
                        return ["models"]  # 使用虚拟的 models 应用名
                    break
        finally:
            del frame
            
        # 如果没有发现，扫描所有已导入的模块
        if not discovered:
            for module_name, module in sys.modules.items():
                if module and hasattr(module, '__dict__'):
                    for attr_name in dir(module):
                        try:
                            attr = getattr(module, attr_name)
                            if (inspect.isclass(attr) and 
                                issubclass(attr, TortoiseModel) and 
                                attr != TortoiseModel and
                                not getattr(attr._meta, 'abstract', False)):
                                if module_name not in discovered:
                                    discovered.append(module_name)
                                break
                        except (AttributeError, TypeError):
                            continue
        
        return discovered or ["models"]
    
    async def create_tables(self, safe: bool = True) -> None:
        """
        创建数据库表
        
        Args:
            safe: 是否安全模式（不删除已存在的表）
        """
        self._ensure_initialized()
        await Tortoise.generate_schemas(safe=safe)
        logger.info("数据库表创建完成")
        
    async def drop_tables(self) -> None:
        """删除所有表"""
        self._ensure_initialized()
        await Tortoise.generate_schemas(safe=False)
        logger.info("数据库表已删除并重新创建")
        
    async def execute_sql(self, sql: str, params: List = None) -> List[Dict]:
        """
        执行原始 SQL 查询
        
        Args:
            sql: SQL 语句
            params: 参数列表
            
        Returns:
            查询结果
        """
        self._ensure_initialized()
        connection = connections.get("default")
        return await connection.execute_query_dict(sql, params or [])
        
    async def execute_script(self, script: str) -> None:
        """
        执行 SQL 脚本
        
        Args:
            script: SQL 脚本内容
        """
        self._ensure_initialized()
        connection = connections.get("default")
        await connection.execute_script(script)
        
    def get_connection_info(self) -> Dict:
        """
        获取连接信息
        
        Returns:
            连接信息字典
        """
        self._ensure_initialized()
        return {
            "config": self._config,
            "apps": list(Tortoise.apps.keys()),
            "models": {
                app_name: list(app_models.keys()) 
                for app_name, app_models in Tortoise.apps.items()
            }
        }
        
    def is_connected(self) -> bool:
        """检查是否已连接"""
        return self._initialized
        
    def _ensure_initialized(self) -> None:
        """确保数据库已初始化"""
        if not self._initialized:
            raise RuntimeError("数据库尚未初始化，请先调用 connect() 方法")


class DatabaseConfig:
    """数据库配置类"""
    
    # 常用数据库 URL 模板
    SQLITE = "sqlite://{path}"
    MYSQL = "mysql://{user}:{password}@{host}:{port}/{database}"
    POSTGRESQL = "postgres://{user}:{password}@{host}:{port}/{database}"
    
    @classmethod
    def sqlite(cls, path: str = "db.sqlite3") -> str:
        """
        创建 SQLite 数据库 URL
        
        Args:
            path: 数据库文件路径
            
        Returns:
            数据库 URL
        """
        return cls.SQLITE.format(path=path)
    
    @classmethod
    def mysql(cls, 
              user: str,
              password: str,
              host: str = "localhost",
              port: int = 3306,
              database: str = "test") -> str:
        """
        创建 MySQL 数据库 URL
        
        Args:
            user: 用户名
            password: 密码
            host: 主机地址
            port: 端口
            database: 数据库名
            
        Returns:
            数据库 URL
        """
        return cls.MYSQL.format(
            user=user,
            password=password,
            host=host,
            port=port,
            database=database
        )
    
    @classmethod
    def postgresql(cls,
                   user: str,
                   password: str,
                   host: str = "localhost",
                   port: int = 5432,
                   database: str = "test") -> str:
        """
        创建 PostgreSQL 数据库 URL
        
        Args:
            user: 用户名
            password: 密码
            host: 主机地址
            port: 端口
            database: 数据库名
            
        Returns:
            数据库 URL
        """
        return cls.POSTGRESQL.format(
            user=user,
            password=password,
            host=host,
            port=port,
            database=database
        )


# 全局数据库实例
database = Database()


# 便捷的装饰器
def with_database(url: str = None, 
                 models: List[str] = None,
                 auto_discover: bool = True,
                 generate_schemas: bool = False):
    """
    数据库连接装饰器
    
    Args:
        url: 数据库连接 URL
        models: 模型模块列表
        auto_discover: 是否自动发现模型类
        generate_schemas: 是否自动生成数据库表结构
    """
    def decorator(func):
        async def wrapper(*args, **kwargs):
            if not database.is_connected():
                await database.connect(url, models, auto_discover, generate_schemas)
            try:
                return await func(*args, **kwargs)
            finally:
                pass  # 保持连接开启，由用户手动关闭
        return wrapper
    return decorator 